package cn.ticsmyc.wheel.aop;


import cn.ticsmyc.wheel.aop.advice.MethodInterceptor;
import cn.ticsmyc.wheel.aop.entity.EnhanceInfo;
import net.sf.cglib.proxy.Enhancer;

import java.lang.reflect.*;

/**
 * @author Ticsmyc
 * @date 2020-12-21 21:52
 */
public class ProxyFactory implements InvocationHandler,net.sf.cglib.proxy.InvocationHandler  {
    //增强对象
    private Object target;
    //增强方法
    private MethodInterceptor advice;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 获取代理类或者原始类型的实例（由注解决定）
     * @return
     */
    public Object getProxy(){

        Object proxyResult=null;
        if(Modifier.isFinal(this.target.getClass().getModifiers())){
            //如果是final类， 只能使用jdk代理
            if(this.target.getClass().getInterfaces().length !=0){
                proxyResult = getJdkProxy(this.target,this);
            }else{
                throw new RuntimeException("无法代理");
            }

        }else{
            //其他情况使用cglib
            proxyResult = getCglibProxy(this.target,this);
        }
        return proxyResult;
    }

    private Object getCglibProxy(Object target, net.sf.cglib.proxy.InvocationHandler aopHandler) {
        Enhancer enhancer = new Enhancer();
        //设置代理类的父类（就是被代理的类）
        enhancer.setSuperclass(target.getClass());
        //设置回调（代理类调用的真实方法（内含aop逻辑））
        enhancer.setCallback(aopHandler);
        return enhancer.create();
    }

    private Object getJdkProxy(Object target, InvocationHandler aopHandler) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),aopHandler);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        //跳过Object方法
        if(Object.class.equals(method.getDeclaringClass())){
            return method.invoke(this,args);
        }
        //开始aop逻辑
        EnhanceInfo enhanceInfo = new EnhanceInfo(proxy,method,args);

        if(advice.preInvoke(enhanceInfo)){
            //前置处理返回true时，后续方法不再执行
            return enhanceInfo.getResult();
        }
        Object result=null;
        try{
            //调用真实业务方法
            System.out.println("*** 调用的方法为"+ method);
            result = method.invoke(target, args);
            enhanceInfo.setResult(result);
            //执行postInvode增强
            advice.postInvoke(enhanceInfo);
            return enhanceInfo.getResult();
        }catch(Exception e){
            enhanceInfo.setException(e);
            //抛出异常时的增强
            advice.postThrowing(enhanceInfo);
            return enhanceInfo.getResult();
        }finally {
            //无论如何都要执行结果返回
            advice.postReturning(enhanceInfo);
        }
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public MethodInterceptor getAdvice() {
        return advice;
    }

    public void setAdvice(MethodInterceptor advice) {
        this.advice = advice;
    }

}
